#include "RedBlackTree.hpp"
#include <string.h>
#include <math.h>
#include <stdio.h>

#define W 6400
#define H 6400
int canvas[H][W];
int R = 90;
int px = 9;
int NW = 7 * px;
int NH = 5 * px;
int linePx = 20;
#define NUMBER_COLOR 3
#define LINE_COLOR 4
#define RED_COLOR 1
#define BLACK_COLOR 2
#define LINE_PX 20
void drawCircle(int ox, int oy, bool red)
{

    int sx = ox - R;
    int ex = ox + R;
    int sy = oy - R;
    int ey = oy + R;
    for (int i = sy; i < H && i < ey; i++)
    {
        for (int j = sx; j < W && j < ex; j++)
        {
            int x = i;
            int y = j;
            if ((pow((ox - y) * 1.0, 2.0) + pow((oy - x) * 1.0, 2.0)) <= pow(R, 2))
            {
                canvas[i][j] = red ? RED_COLOR : BLACK_COLOR;
            }
        }
    }
}
void drawNumber(int ox, int oy, int text, bool left)
{
    int sx, ex, sy, ey;
    if (left)
    {
        sx = ox - (3 * px);
        sy = oy - (2 * px);
    }
    else
    {
        sx = ox + px;
        sy = oy - (2 * px);
    }
    if (text == 1)
    {
        ex = sx + px;
        ey = sy + (5 * px);
        for (int h = sy; h < W && h < ey; h++)
        {
            for (int w = sx; w < H && w < ex; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
    }
    if (text == 2)
    {
        for (int h = sy; h < W && h < (sy + px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 2 * px; h < W && h < (sy + 3 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 4 * px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }

        for (int h = sy; h < W && h < (sy + 2 * px); h++)
        {
            for (int w = sx + 2 * px; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 3 * px; h < W && h < (sy + 4 * px); h++)
        {
            for (int w = sx; w < H && w < sx + px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
    }
    if (text == 3)
    {
        for (int h = sy; h < W && h < (sy + px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 2 * px; h < W && h < (sy + 3 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 4 * px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }

        for (int h = sy; h < W && h < (sy + 2 * px); h++)
        {
            for (int w = sx + 2 * px; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 3 * px; h < W && h < (sy + 4 * px); h++)
        {
            for (int w = sx + 2 * px; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
    }
    if (text == 4)
    {
        for (int h = sy; h < W && h < (sy + 3 * px); h++)
        {
            for (int w = sx; w < H && w < sx + px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx + 2 * px; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 2 * px; h < W && h < (sy + 3 * px); h++)
        {
            for (int w = sx + 1 * px; w < H && w < sx + 2 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
    }
    if (text == 5)
    {
        for (int h = sy; h < W && h < (sy + px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 2 * px; h < W && h < (sy + 3 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 4 * px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }

        for (int h = sy; h < W && h < (sy + 2 * px); h++)
        {
            for (int w = sx; w < H && w < sx + px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 3 * px; h < W && h < (sy + 4 * px); h++)
        {
            for (int w = sx + 2 * px; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
    }
    if (text == 6)
    {
        for (int h = sy; h < W && h < (sy + px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 2 * px; h < W && h < (sy + 3 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 4 * px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + px; h < W && h < (sy + 2 * px); h++)
        {
            for (int w = sx; w < H && w < sx + px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx; w < H && w < sx + px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 3 * px; h < W && h < (sy + 4 * px); h++)
        {
            for (int w = sx + 2 * px; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
    }
    if (text == 7)
    {
        for (int h = sy; h < W && h < (sy + px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx + 2 * px; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
    }
    if (text == 8)
    {
        for (int h = sy; h < W && h < (sy + px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 2 * px; h < W && h < (sy + 3 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 4 * px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx; w < H && w < sx + px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx + 2 * px; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
    }
    if (text == 9)
    {
        for (int h = sy; h < W && h < (sy + px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 2 * px; h < W && h < (sy + 3 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + px; h < W && h < (sy + 2 * px); h++)
        {
            for (int w = sx; w < H && w < sx + px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx + 2 * px; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 4 * px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
    }
    if (text == 0)
    {
        for (int h = sy; h < W && h < (sy + px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + 4 * px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx; w < H && w < sx + px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
        for (int h = sy + px; h < W && h < (sy + 5 * px); h++)
        {
            for (int w = sx + 2 * px; w < H && w < sx + 3 * px; w++)
            {
                canvas[h][w] = NUMBER_COLOR;
            }
        }
    }
}
void writeFile()
{
    FILE *fp = fopen("./RBT.ppm", "w");
    fprintf(fp, "P6\n %d %d 255\n", W, H);
    for (int i = 0; i < W; i++)
    {
        for (int j = 0; j < W; j++)
        {
            if (canvas[i][j] == 0)
            {
                fputc(255, fp);
                fputc(255, fp);
                fputc(255, fp);
            }
            else if (canvas[i][j] == RED_COLOR)
            {
                fputc(255, fp);
                fputc(0, fp);
                fputc(0, fp);
            }
            if (canvas[i][j] == BLACK_COLOR)
            {
                fputc(0, fp);
                fputc(0, fp);
                fputc(0, fp);
            }
            if (canvas[i][j] == NUMBER_COLOR)
            {
                fputc(51, fp);
                fputc(102, fp);
                fputc(255, fp);
            }
            if (canvas[i][j] == LINE_COLOR)
            {
                fputc(0, fp);
                fputc(0, fp);
                fputc(0, fp);
            }
        }
    }
    fclose(fp);
}
int getTreeDeepth(TreeNode *treeNode)
{
    int lh = 0, rh = 0;
    if (treeNode->left == NULL && treeNode->right == NULL)
    {
        return 1;
    }
    if (treeNode->left != NULL)
    {
        lh = 1 + getTreeDeepth(treeNode->left);
    }
    if (treeNode->right != NULL)
    {

        rh = 1 + getTreeDeepth(treeNode->right);
    }
    return lh > rh ? lh : rh;
}

void drawLeftLine(int p0x, int p0y, int p1x, int p1y)
{
    double tanA = ((p1y - p0y) * 1.0) / ((p0x - p1x) * 1.0);
    for (int i = p0x; i < W && i > p1x; i--)
    {
        int js = p1y - tanA * (i - p1x);
        for (int j = js; j < H && j < js + LINE_PX; j++)
        {
            if (canvas[j][i] == 0)
                canvas[j][i] = LINE_COLOR;
        }
    }
}
void drawRightLine(int p0x, int p0y, int p1x, int p1y)
{
    double tanA = ((p1y - p0y) * 1.0) / ((p1x - p0x) * 1.0);
    for (int i = p0x; i < p1x && i < W; i++)
    {
        int js = p1y - tanA * (p1x - i);
        for (int j = js; j < H && j < js + LINE_PX; j++)
        {
            if (canvas[j][i] == 0)
                canvas[j][i] = LINE_COLOR;
        }
    }
}

void drawTree(TreeNode *root, int ox, int oy, int maxDeep, int curDeep)
{
    int it = (maxDeep - curDeep + 1) * 3;
    int ht = 3;
    if (root->right != NULL)
    {
        int x = ox + R * it;
        int y = oy + R * ht;
        drawCircle(x, y, root->right->red);
        int number = atoi(root->right->data);
        drawNumber(x, y, number / 10, true);
        drawNumber(x, y, number % 10, false);
        drawRightLine(ox, oy, x, y);
        drawTree(root->right, x, y, maxDeep, curDeep + 1);
    }
    if (root->left != NULL)
    {
        int x = ox - R * it;
        int y = oy + R * ht;
        drawCircle(x, y, root->left->red);
        int number = atoi(root->left->data);
        drawNumber(x, y, number / 10, true);
        drawNumber(x, y, number % 10, false);
        drawLeftLine(ox, oy, x, y);
        drawTree(root->left, x, y, maxDeep, curDeep + 1);
    }
}
int main()
{
    TreeNode *root = buildNode(nullptr, "56");
    TreeNode *p = buildNode(root, "48");
    balanceInsertion(root, p);
    p = buildNode(root, "63");
    balanceInsertion(root, p);
    p = buildNode(root, "49");
    balanceInsertion(root, p);
    p = buildNode(root, "47");
    balanceInsertion(root, p);
    p = buildNode(root, "64");
    balanceInsertion(root, p);
    p = buildNode(root, "62");
    balanceInsertion(root, p);
    p = buildNode(root, "89");
    balanceInsertion(root, p);
    p = buildNode(root, "90");
    balanceInsertion(root, p);
    p = buildNode(root, "91");
    balanceInsertion(root, p);

    int deepth = getTreeDeepth(root);
    int ox = W / 2;
    int oy = R + 200;
    drawCircle(ox, oy, root->red);
    int number = atoi(root->data);
    drawNumber(ox, oy, number / 10, true);
    drawNumber(ox, oy, number % 10, false);
    drawTree(root, ox, oy, deepth, 2);
    writeFile();
}